﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MethodWorx.CMS.TemplateParser
{
    public abstract class TemplateNode
    {
        private List<TemplateNode> nodes = new List<TemplateNode>();

        public string Name { get; set; }
        public TemplateNode Parent { get; private set; }
        public TemplateNode PreviousSibling { get; private set; }
        public string Error { get; internal set; }

        public string ParsedBuffer { get; set; }

        public void AddNode(TemplateNode current)
        {
            current.Parent = this;
            if(nodes.Any())
                current.PreviousSibling = nodes.Last();
            nodes.Add(current);
        }

        public void AddNodes(IEnumerable<TemplateNode> nodes)
        {
            foreach(var node in nodes)
                this.AddNode(node);
        }

        public IEnumerable<TemplateNode> Children
        {
            get
            {
                foreach(var node in this.nodes)
                {
                    if(node is TemplateText)
                    {
                        if (!string.IsNullOrEmpty(((TemplateText)node).Text) || !string.IsNullOrEmpty(node.Error))
                            yield return node;
                    }
                    else if(node is TemplateAttribute)
                    {
                        if (!(string.IsNullOrEmpty((((TemplateAttribute)node).Name ?? "").Trim())) || !string.IsNullOrEmpty(node.Error))
                            yield return node;
                    }
                    else
                        yield return node;
                }
            }
        }

        public IEnumerable<TemplateNode> GetErrors()
        {
            if (!string.IsNullOrEmpty(this.Error))
                yield return this;

            foreach(var child in this.Children)
            {
                foreach(var error in child.GetErrors())
                {
                    yield return error;
                }
            }
        }

        private IEnumerable<TemplateNode> FlattenNodes(TemplateNode parent)
        {
            foreach (var child in parent.Children)
            {
                yield return child;
                foreach (var subChild in this.FlattenNodes(child))
                    yield return subChild;
            }
        }

      
        public IEnumerable<T> FlattenNodes<T>()
            where T : TemplateNode
        {
            return this.FlattenNodes(this).OfType<T>().ToArray();
        }


        internal int Remove()
        {
            int i = this.Parent.nodes.IndexOf(this);
            this.Parent.nodes.Remove(this);
            return i;
        }

        public void InsertAt(IEnumerable<TemplateNode> nodesToinsert, int index)
        {
            foreach (var childNode in nodesToinsert)
            {
                this.nodes.Insert(index, childNode);
                childNode.Parent = this;
                index++;
            }
        }

        public int Offset { get; internal set; }
        public int EndOffset { get; internal set; }

        public void InsertAt(TemplateNode node, int index)
        {
            this.nodes.Insert(index, node);
            node.Parent = this;
        }
    }
}
